use crate::errors::MyError;
use std::time::{SystemTime, UNIX_EPOCH};
use uuid::Uuid;

pub fn gen_uuid() -> String {
    let uid = Uuid::new_v4();
    uid.to_string()
}

pub fn is_not_empty_or<'a>(this: &'a str, or_val: &'a str) -> &'a str {
    if this.is_empty() {
        or_val
    } else {
        this
    }
}
pub fn to_ticks(time: &SystemTime) -> Result<u32, MyError> {
    let since_epoch = time.duration_since(UNIX_EPOCH)?;
    Ok(since_epoch.as_secs().try_into()?)
}
pub fn to_now_ticks() -> Result<u32, MyError> {
    to_ticks(&SystemTime::now())
}
type NodePos = (usize, usize);
fn move_by_node(content: &str, start_pos: usize) -> Option<NodePos> {
    let start = content[start_pos..].find('<')?;
    let end = content[start_pos + start..].find('>')?;

    Some((start_pos + start, start_pos + start + end + 1))
}
fn get_node_name<'a>(content: &'a str, node_pos: &'a NodePos) -> Option<&'a str> {
    let result: Vec<&str> = content[node_pos.0..node_pos.1]
        .trim_start_matches('<')
        .trim_start_matches('/')
        .trim_end_matches('>')
        .trim_end_matches('/')
        .split(' ')
        .collect();
    Some(result.first()?)
}
fn is_close_node(content: &str, node_pos: &NodePos) -> bool {
    content[node_pos.0..node_pos.1].starts_with("</")
        || content[node_pos.0..node_pos.1].ends_with("/>")
}
fn is_single_node(content: &str, node_pos: &NodePos) -> bool {
    (content[node_pos.0..node_pos.1].starts_with('<')
        && content[node_pos.0..node_pos.1].ends_with("/>"))
        || content[node_pos.0..node_pos.1].eq("<br>")
}

#[derive(Default, Clone, Debug)]
struct MyNode {
    start: Option<NodePos>,
    end: Option<NodePos>,
    children: Vec<MyNode>,
}

fn flatten_nodes(nodes: &[MyNode], nodes_pos: &mut Vec<NodePos>) -> Option<()> {
    for node in nodes {
        nodes_pos.push(node.start?);
        if !node.is_simple() {
            flatten_nodes(&node.children, nodes_pos);
            nodes_pos.push(node.end?);
        }
    }
    Some(())
}
impl MyNode {
    fn new() -> Self {
        MyNode::default()
    }
    fn is_simple(&self) -> bool {
        self.start == self.end
    }
    fn read(&mut self, content: &str, start_pos: Option<usize>) -> Option<()> {
        // 要确保读到的第一个节点是一个开始节点
        let mut node_pos = move_by_node(content, start_pos.unwrap_or(0))?;
        if is_single_node(content, &node_pos) {
            // 如果第一个节点是封闭节点，那么直接退出
            self.start = Some(node_pos);
            self.end = Some(node_pos);
            //println!("return end:{:?}", node_pos);
            return Some(());
        }
        if is_close_node(content, &node_pos) {
            // 如果第一个节点是关闭节点，那么继续再读一次
            node_pos = move_by_node(content, node_pos.1)?;
        }
        if is_close_node(content, &node_pos) {
            // 如果读2次都是closeNode，说明有语法错误
            return None;
        }

        // 成功记录开始节点, 后面的处理是添加children和找到关闭节点
        self.start = Some(node_pos);

        let mut next_start = node_pos.1;

        while next_start != 0 {
            let node_pos1 = move_by_node(content, next_start)?;
            if is_single_node(content, &node_pos1) {
                // 如果是封闭节点，那么直接添加到children
                let mut new_node = MyNode::new();
                new_node.start = Some(node_pos1);
                new_node.end = Some(node_pos1);
                self.children.push(new_node.clone());

                next_start = new_node.clone().end.unwrap().1;
                continue;
            }
            if is_close_node(content, &node_pos1) {
                // 如果是关闭节点，那么结束遍历，退出
                self.end = Some(node_pos1);
                return Some(());
            }

            // 说明是一个开始节点, 往下一层读取
            let mut new_node = MyNode::new();
            new_node.read(content, Some(next_start));
            next_start = new_node.clone().end.unwrap().1;
            //println!("while next_start:{:?}", next_start);
            self.children.push(new_node.clone());
        }
        Some(())
    }

    fn get_text(&self, content: &str) -> Option<String> {
        let mut nodes_pos: Vec<NodePos> = vec![];

        nodes_pos.push(self.start?);
        flatten_nodes(&self.children, &mut nodes_pos)?;
        nodes_pos.push(self.end?);

        // 参见测试用例:test_get_title_6
        if self.start?.0 > 0 {
            return Some(content[0..self.start?.0].to_string());
        }

        let len = nodes_pos.len() - 1;
        let mut content_pos: Vec<(usize, usize)> = vec![];
        for n in 0..len {
            content_pos.push((nodes_pos[n].1, nodes_pos[n + 1].0));
        }

        let result = content_pos
            .iter()
            .map(|node_pos| content[node_pos.0..node_pos.1].to_string())
            .collect::<String>();
        Some(result)
    }
}

pub fn get_title(content: &str) -> Option<String> {
    let mut node: MyNode = MyNode::new();
    // 参见测试用例:test_get_title_7
    if node.read(content, Some(0)).is_none() {
        return Some(content.to_string());
    }
    node.get_text(content)
}
#[test]
fn test_get_title_1() {
    assert_eq!(get_title("<div>abcd</div>"), Some("abcd".to_string()));
}
#[test]
fn test_get_title_2() {
    assert_eq!(get_title("<div>abc<br/>d</div>"), Some("abcd".to_string()));
}
#[test]
fn test_get_title_3() {
    assert_eq!(
        get_title(r#"<div>ab<div><image src="abcdefd"/></div>cd</div>"#),
        Some("abcd".to_string())
    );
}
#[test]
fn test_get_title_4() {
    assert_eq!(
        get_title(r#"<div>jjjjjjjjj</div><div><br/></div><div>fffffffff</div>"#),
        Some("jjjjjjjjj".to_string())
    );
}
#[test]
fn test_get_title_5() {
    assert_eq!(
        get_title(r#"<div>jjj<br>jjjjjj</div><div><br/></div><div>fffffffff</div>"#),
        Some("jjjjjjjjj".to_string())
    );
}
#[test]
fn test_get_title_6() {
    assert_eq!(
        get_title(r#"你好<div>jjj<br>jjjjjj</div><div><br/></div><div>fffffffff</div>"#),
        Some("你好".to_string())
    );
}
#[test]
fn test_get_title_7() {
    assert_eq!(get_title("第三次测试"), Some("第三次测试".to_string()));
}
